//
//  HelloWorldWrapper.m
//  crossLanguage
//
//  Created by Yao Yuan on 6/4/2023.
//

#import <Foundation/Foundation.h>
#import "HelloWorldWrapper.h"
#import "HelloWorld.hpp"
#import "CustomObject.h"
#import "CustomObjectCpp.hpp"

@implementation HelloWorldWrapper

- (void) executeCallBack : (void (*)())fp {
    HelloWorld helloWorld;
    HelloWorld::callback_t callback = fp;
    helloWorld.ExecuteCallback(callback);
}

- (NSString *) sayHello {
    HelloWorld helloWorld;
    std::string helloWorldMessage = helloWorld.sayHello();
    return [NSString
            stringWithCString:helloWorldMessage.c_str()
            encoding:NSUTF8StringEncoding];
}

- (void) benchmarkZero {
    HelloWorld helloWorld;
    helloWorld.BenchmarkZero();
}

- (void) benchmarkOne:(NSInteger)a {
    HelloWorld helloWorld;
    helloWorld.BenchmarkOne(int64_t(a));
}

- (void) benchmarkTwo:(NSInteger)a :(NSInteger)b {
    HelloWorld helloWorld;
    helloWorld.BenchmarkTwo(int64_t(a), int64_t(b));
}

- (void) benchmarkThree:(NSInteger)a :(NSInteger)b :(NSInteger)c {
    HelloWorld helloWorld;
    helloWorld.BenchmarkThree(int64_t(a), int64_t(b), int64_t(c));
}

- (void) benchmarkFour:(NSInteger)a :(NSInteger)b :(NSInteger)c :(NSInteger)d {
    HelloWorld helloWorld;
    helloWorld.BenchmarkFour(int64_t(a), int64_t(b), int64_t(c), int64_t(d));
}

- (void) benchmarkFive:(NSInteger)a :(NSInteger)b :(NSInteger)c :(NSInteger)d :(NSInteger)e {
    HelloWorld helloWorld;
    helloWorld.BenchmarkFive(int64_t(a), int64_t(b), int64_t(c), int64_t(d), int64_t(e));
}

- (void) benchmarkSix:(NSInteger)a :(NSInteger)b :(NSInteger)c :(NSInteger)d :(NSInteger)e :(NSInteger)f {
    HelloWorld helloWorld;
    helloWorld.BenchmarkSix(int64_t(a), int64_t(b), int64_t(c), int64_t(d), int64_t(e), int64_t(f));
}

- (void) benchmarkSeven:(NSInteger)a :(NSInteger)b :(NSInteger)c :(NSInteger)d :(NSInteger)e :(NSInteger)f :(NSInteger)g {
    HelloWorld helloWorld;
    helloWorld.BenchmarkSeven(int64_t(a), int64_t(b), int64_t(c), int64_t(d), int64_t(e), int64_t(f), int64_t(g));
}

- (void) benchmarkEight:(NSInteger)a :(NSInteger)b :(NSInteger)c :(NSInteger)d :(NSInteger)e :(NSInteger)f :(NSInteger)g :(NSInteger)h {
    HelloWorld helloWorld;
    helloWorld.BenchmarkEight(int64_t(a), int64_t(b), int64_t(c), int64_t(d), int64_t(e), int64_t(f), int64_t(g), int64_t(h));
}

- (void) benchmarkNine:(NSInteger)a :(NSInteger)b :(NSInteger)c :(NSInteger)d :(NSInteger)e :(NSInteger)f :(NSInteger)g :(NSInteger)h :(NSInteger)i {
    HelloWorld helloWorld;
    helloWorld.BenchmarkNine(int64_t(a), int64_t(b), int64_t(c), int64_t(d), int64_t(e), int64_t(f), int64_t(g), int64_t(h), int64_t(i));
}

- (void) benchmarkTen:(NSInteger)a :(NSInteger)b :(NSInteger)c :(NSInteger)d :(NSInteger)e :(NSInteger)f :(NSInteger)g :(NSInteger)h :(NSInteger)i :(NSInteger)j {
    HelloWorld helloWorld;
    helloWorld.BenchmarkTen(int64_t(a), int64_t(b), int64_t(c), int64_t(d), int64_t(e), int64_t(f), int64_t(g), int64_t(h), int64_t(i), int64_t(j));
}

- (void) benchmarkObjectOne:(CustomObject*) obj{
    HelloWorld helloWorld;
    CustomObjectCpp *objCpp = new CustomObjectCpp();
    objCpp->value1 = std::string([obj.value1 UTF8String]);
    objCpp->value2 = std::string([obj.value2 UTF8String]);
    objCpp->value3 = std::string([obj.value3 UTF8String]);
    helloWorld.BenchmarkObjectOne(objCpp);
}

- (void) benchmarkObjectTwo:(CustomObject*) a :(CustomObject*) b{
    HelloWorld helloWorld;
    CustomObjectCpp *aCpp = new CustomObjectCpp();
    aCpp->value1 = std::string([a.value1 UTF8String]);
    aCpp->value2 = std::string([a.value2 UTF8String]);
    aCpp->value3 = std::string([a.value3 UTF8String]);
    CustomObjectCpp *bCpp = new CustomObjectCpp();
    bCpp->value1 = std::string([b.value1 UTF8String]);
    bCpp->value2 = std::string([b.value2 UTF8String]);
    bCpp->value3 = std::string([b.value3 UTF8String]);
    helloWorld.BenchmarkObjectTwo(aCpp, bCpp);
}

- (void) benchmarkObjectThree:(CustomObject*) a :(CustomObject*) b :(CustomObject*) c{
    HelloWorld helloWorld;
    CustomObjectCpp *aCpp = new CustomObjectCpp();
    aCpp->value1 = std::string([a.value1 UTF8String]);
    aCpp->value2 = std::string([a.value2 UTF8String]);
    aCpp->value3 = std::string([a.value3 UTF8String]);
    CustomObjectCpp *bCpp = new CustomObjectCpp();
    bCpp->value1 = std::string([b.value1 UTF8String]);
    bCpp->value2 = std::string([b.value2 UTF8String]);
    bCpp->value3 = std::string([b.value3 UTF8String]);
    CustomObjectCpp *cCpp = new CustomObjectCpp();
    cCpp->value1 = std::string([c.value1 UTF8String]);
    cCpp->value2 = std::string([c.value2 UTF8String]);
    cCpp->value3 = std::string([c.value3 UTF8String]);
    helloWorld.BenchmarkObjectThree(aCpp, bCpp, cCpp);
}

- (void) benchmarkObjectFour:(CustomObject*) a :(CustomObject*) b :(CustomObject*) c :(CustomObject*) d{
    HelloWorld helloWorld;
    CustomObjectCpp *aCpp = new CustomObjectCpp();
    aCpp->value1 = std::string([a.value1 UTF8String]);
    aCpp->value2 = std::string([a.value2 UTF8String]);
    aCpp->value3 = std::string([a.value3 UTF8String]);
    CustomObjectCpp *bCpp = new CustomObjectCpp();
    bCpp->value1 = std::string([b.value1 UTF8String]);
    bCpp->value2 = std::string([b.value2 UTF8String]);
    bCpp->value3 = std::string([b.value3 UTF8String]);
    CustomObjectCpp *cCpp = new CustomObjectCpp();
    cCpp->value1 = std::string([c.value1 UTF8String]);
    cCpp->value2 = std::string([c.value2 UTF8String]);
    cCpp->value3 = std::string([c.value3 UTF8String]);
    CustomObjectCpp *dCpp = new CustomObjectCpp();
    dCpp->value1 = std::string([d.value1 UTF8String]);
    dCpp->value2 = std::string([d.value2 UTF8String]);
    dCpp->value3 = std::string([d.value3 UTF8String]);
    helloWorld.BenchmarkObjectFour(aCpp, bCpp, cCpp, dCpp);
}

- (void) benchmarkObjectFive:(CustomObject*) a :(CustomObject*) b :(CustomObject*) c :(CustomObject*) d :(CustomObject*) e{
    HelloWorld helloWorld;
    CustomObjectCpp *aCpp = new CustomObjectCpp();
    aCpp->value1 = std::string([a.value1 UTF8String]);
    aCpp->value2 = std::string([a.value2 UTF8String]);
    aCpp->value3 = std::string([a.value3 UTF8String]);
    CustomObjectCpp *bCpp = new CustomObjectCpp();
    bCpp->value1 = std::string([b.value1 UTF8String]);
    bCpp->value2 = std::string([b.value2 UTF8String]);
    bCpp->value3 = std::string([b.value3 UTF8String]);
    CustomObjectCpp *cCpp = new CustomObjectCpp();
    cCpp->value1 = std::string([c.value1 UTF8String]);
    cCpp->value2 = std::string([c.value2 UTF8String]);
    cCpp->value3 = std::string([c.value3 UTF8String]);
    CustomObjectCpp *dCpp = new CustomObjectCpp();
    dCpp->value1 = std::string([d.value1 UTF8String]);
    dCpp->value2 = std::string([d.value2 UTF8String]);
    dCpp->value3 = std::string([d.value3 UTF8String]);
    CustomObjectCpp *eCpp = new CustomObjectCpp();
    eCpp->value1 = std::string([e.value1 UTF8String]);
    eCpp->value2 = std::string([e.value2 UTF8String]);
    eCpp->value3 = std::string([e.value3 UTF8String]);
    helloWorld.BenchmarkObjectFive(aCpp, bCpp, cCpp, dCpp, eCpp);
}

- (void) benchmarkObjectSix:(CustomObject*) a :(CustomObject*) b :(CustomObject*) c :(CustomObject*) d :(CustomObject*) e :(CustomObject*) f{
    HelloWorld helloWorld;
    CustomObjectCpp *aCpp = new CustomObjectCpp();
    aCpp->value1 = std::string([a.value1 UTF8String]);
    aCpp->value2 = std::string([a.value2 UTF8String]);
    aCpp->value3 = std::string([a.value3 UTF8String]);
    CustomObjectCpp *bCpp = new CustomObjectCpp();
    bCpp->value1 = std::string([b.value1 UTF8String]);
    bCpp->value2 = std::string([b.value2 UTF8String]);
    bCpp->value3 = std::string([b.value3 UTF8String]);
    CustomObjectCpp *cCpp = new CustomObjectCpp();
    cCpp->value1 = std::string([c.value1 UTF8String]);
    cCpp->value2 = std::string([c.value2 UTF8String]);
    cCpp->value3 = std::string([c.value3 UTF8String]);
    CustomObjectCpp *dCpp = new CustomObjectCpp();
    dCpp->value1 = std::string([d.value1 UTF8String]);
    dCpp->value2 = std::string([d.value2 UTF8String]);
    dCpp->value3 = std::string([d.value3 UTF8String]);
    CustomObjectCpp *eCpp = new CustomObjectCpp();
    eCpp->value1 = std::string([e.value1 UTF8String]);
    eCpp->value2 = std::string([e.value2 UTF8String]);
    eCpp->value3 = std::string([e.value3 UTF8String]);
    CustomObjectCpp *fCpp = new CustomObjectCpp();
    fCpp->value1 = std::string([f.value1 UTF8String]);
    fCpp->value2 = std::string([f.value2 UTF8String]);
    fCpp->value3 = std::string([f.value3 UTF8String]);
    helloWorld.BenchmarkObjectSix(aCpp, bCpp, cCpp, dCpp, eCpp, fCpp);
}

- (void) benchmarkObjectSeven:(CustomObject*) a :(CustomObject*) b :(CustomObject*) c :(CustomObject*) d :(CustomObject*) e :(CustomObject*) f :(CustomObject*) g{
    HelloWorld helloWorld;
    CustomObjectCpp *aCpp = new CustomObjectCpp();
    aCpp->value1 = std::string([a.value1 UTF8String]);
    aCpp->value2 = std::string([a.value2 UTF8String]);
    aCpp->value3 = std::string([a.value3 UTF8String]);
    CustomObjectCpp *bCpp = new CustomObjectCpp();
    bCpp->value1 = std::string([b.value1 UTF8String]);
    bCpp->value2 = std::string([b.value2 UTF8String]);
    bCpp->value3 = std::string([b.value3 UTF8String]);
    CustomObjectCpp *cCpp = new CustomObjectCpp();
    cCpp->value1 = std::string([c.value1 UTF8String]);
    cCpp->value2 = std::string([c.value2 UTF8String]);
    cCpp->value3 = std::string([c.value3 UTF8String]);
    CustomObjectCpp *dCpp = new CustomObjectCpp();
    dCpp->value1 = std::string([d.value1 UTF8String]);
    dCpp->value2 = std::string([d.value2 UTF8String]);
    dCpp->value3 = std::string([d.value3 UTF8String]);
    CustomObjectCpp *eCpp = new CustomObjectCpp();
    eCpp->value1 = std::string([e.value1 UTF8String]);
    eCpp->value2 = std::string([e.value2 UTF8String]);
    eCpp->value3 = std::string([e.value3 UTF8String]);
    CustomObjectCpp *fCpp = new CustomObjectCpp();
    fCpp->value1 = std::string([f.value1 UTF8String]);
    fCpp->value2 = std::string([f.value2 UTF8String]);
    fCpp->value3 = std::string([f.value3 UTF8String]);
    CustomObjectCpp *gCpp = new CustomObjectCpp();
    gCpp->value1 = std::string([g.value1 UTF8String]);
    gCpp->value2 = std::string([g.value2 UTF8String]);
    gCpp->value3 = std::string([g.value3 UTF8String]);
    helloWorld.BenchmarkObjectSeven(aCpp, bCpp, cCpp, dCpp, eCpp, fCpp, gCpp);
}

- (void) benchmarkObjectEight:(CustomObject*) a :(CustomObject*) b :(CustomObject*) c :(CustomObject*) d :(CustomObject*) e :(CustomObject*) f :(CustomObject*) g :(CustomObject*) h{
    HelloWorld helloWorld;
    CustomObjectCpp *aCpp = new CustomObjectCpp();
    aCpp->value1 = std::string([a.value1 UTF8String]);
    aCpp->value2 = std::string([a.value2 UTF8String]);
    aCpp->value3 = std::string([a.value3 UTF8String]);
    CustomObjectCpp *bCpp = new CustomObjectCpp();
    bCpp->value1 = std::string([b.value1 UTF8String]);
    bCpp->value2 = std::string([b.value2 UTF8String]);
    bCpp->value3 = std::string([b.value3 UTF8String]);
    CustomObjectCpp *cCpp = new CustomObjectCpp();
    cCpp->value1 = std::string([c.value1 UTF8String]);
    cCpp->value2 = std::string([c.value2 UTF8String]);
    cCpp->value3 = std::string([c.value3 UTF8String]);
    CustomObjectCpp *dCpp = new CustomObjectCpp();
    dCpp->value1 = std::string([d.value1 UTF8String]);
    dCpp->value2 = std::string([d.value2 UTF8String]);
    dCpp->value3 = std::string([d.value3 UTF8String]);
    CustomObjectCpp *eCpp = new CustomObjectCpp();
    eCpp->value1 = std::string([e.value1 UTF8String]);
    eCpp->value2 = std::string([e.value2 UTF8String]);
    eCpp->value3 = std::string([e.value3 UTF8String]);
    CustomObjectCpp *fCpp = new CustomObjectCpp();
    fCpp->value1 = std::string([f.value1 UTF8String]);
    fCpp->value2 = std::string([f.value2 UTF8String]);
    fCpp->value3 = std::string([f.value3 UTF8String]);
    CustomObjectCpp *gCpp = new CustomObjectCpp();
    gCpp->value1 = std::string([g.value1 UTF8String]);
    gCpp->value2 = std::string([g.value2 UTF8String]);
    gCpp->value3 = std::string([g.value3 UTF8String]);
    CustomObjectCpp *hCpp = new CustomObjectCpp();
    hCpp->value1 = std::string([h.value1 UTF8String]);
    hCpp->value2 = std::string([h.value2 UTF8String]);
    hCpp->value3 = std::string([h.value3 UTF8String]);
    helloWorld.BenchmarkObjectEight(aCpp, bCpp, cCpp, dCpp, eCpp, fCpp, gCpp, hCpp);
}

- (void) benchmarkObjectNine:(CustomObject*) a :(CustomObject*) b :(CustomObject*) c :(CustomObject*) d :(CustomObject*) e :(CustomObject*) f :(CustomObject*) g :(CustomObject*) h :(CustomObject*) i{
    HelloWorld helloWorld;
    CustomObjectCpp *aCpp = new CustomObjectCpp();
    aCpp->value1 = std::string([a.value1 UTF8String]);
    aCpp->value2 = std::string([a.value2 UTF8String]);
    aCpp->value3 = std::string([a.value3 UTF8String]);
    CustomObjectCpp *bCpp = new CustomObjectCpp();
    bCpp->value1 = std::string([b.value1 UTF8String]);
    bCpp->value2 = std::string([b.value2 UTF8String]);
    bCpp->value3 = std::string([b.value3 UTF8String]);
    CustomObjectCpp *cCpp = new CustomObjectCpp();
    cCpp->value1 = std::string([c.value1 UTF8String]);
    cCpp->value2 = std::string([c.value2 UTF8String]);
    cCpp->value3 = std::string([c.value3 UTF8String]);
    CustomObjectCpp *dCpp = new CustomObjectCpp();
    dCpp->value1 = std::string([d.value1 UTF8String]);
    dCpp->value2 = std::string([d.value2 UTF8String]);
    dCpp->value3 = std::string([d.value3 UTF8String]);
    CustomObjectCpp *eCpp = new CustomObjectCpp();
    eCpp->value1 = std::string([e.value1 UTF8String]);
    eCpp->value2 = std::string([e.value2 UTF8String]);
    eCpp->value3 = std::string([e.value3 UTF8String]);
    CustomObjectCpp *fCpp = new CustomObjectCpp();
    fCpp->value1 = std::string([f.value1 UTF8String]);
    fCpp->value2 = std::string([f.value2 UTF8String]);
    fCpp->value3 = std::string([f.value3 UTF8String]);
    CustomObjectCpp *gCpp = new CustomObjectCpp();
    gCpp->value1 = std::string([g.value1 UTF8String]);
    gCpp->value2 = std::string([g.value2 UTF8String]);
    gCpp->value3 = std::string([g.value3 UTF8String]);
    CustomObjectCpp *hCpp = new CustomObjectCpp();
    hCpp->value1 = std::string([h.value1 UTF8String]);
    hCpp->value2 = std::string([h.value2 UTF8String]);
    hCpp->value3 = std::string([h.value3 UTF8String]);
    CustomObjectCpp *iCpp = new CustomObjectCpp();
    iCpp->value1 = std::string([i.value1 UTF8String]);
    iCpp->value2 = std::string([i.value2 UTF8String]);
    iCpp->value3 = std::string([i.value3 UTF8String]);
    helloWorld.BenchmarkObjectNine(aCpp, bCpp, cCpp, dCpp, eCpp, fCpp, gCpp, hCpp, iCpp);
}

- (void) benchmarkObjectTen:(CustomObject*) a :(CustomObject*) b :(CustomObject*) c :(CustomObject*) d :(CustomObject*) e :(CustomObject*) f :(CustomObject*) g :(CustomObject*) h :(CustomObject*) i :(CustomObject*) j{
    HelloWorld helloWorld;
    CustomObjectCpp *aCpp = new CustomObjectCpp();
    aCpp->value1 = std::string([a.value1 UTF8String]);
    aCpp->value2 = std::string([a.value2 UTF8String]);
    aCpp->value3 = std::string([a.value3 UTF8String]);
    CustomObjectCpp *bCpp = new CustomObjectCpp();
    bCpp->value1 = std::string([b.value1 UTF8String]);
    bCpp->value2 = std::string([b.value2 UTF8String]);
    bCpp->value3 = std::string([b.value3 UTF8String]);
    CustomObjectCpp *cCpp = new CustomObjectCpp();
    cCpp->value1 = std::string([c.value1 UTF8String]);
    cCpp->value2 = std::string([c.value2 UTF8String]);
    cCpp->value3 = std::string([c.value3 UTF8String]);
    CustomObjectCpp *dCpp = new CustomObjectCpp();
    dCpp->value1 = std::string([d.value1 UTF8String]);
    dCpp->value2 = std::string([d.value2 UTF8String]);
    dCpp->value3 = std::string([d.value3 UTF8String]);
    CustomObjectCpp *eCpp = new CustomObjectCpp();
    eCpp->value1 = std::string([e.value1 UTF8String]);
    eCpp->value2 = std::string([e.value2 UTF8String]);
    eCpp->value3 = std::string([e.value3 UTF8String]);
    CustomObjectCpp *fCpp = new CustomObjectCpp();
    fCpp->value1 = std::string([f.value1 UTF8String]);
    fCpp->value2 = std::string([f.value2 UTF8String]);
    fCpp->value3 = std::string([f.value3 UTF8String]);
    CustomObjectCpp *gCpp = new CustomObjectCpp();
    gCpp->value1 = std::string([g.value1 UTF8String]);
    gCpp->value2 = std::string([g.value2 UTF8String]);
    gCpp->value3 = std::string([g.value3 UTF8String]);
    CustomObjectCpp *hCpp = new CustomObjectCpp();
    hCpp->value1 = std::string([h.value1 UTF8String]);
    hCpp->value2 = std::string([h.value2 UTF8String]);
    hCpp->value3 = std::string([h.value3 UTF8String]);
    CustomObjectCpp *iCpp = new CustomObjectCpp();
    iCpp->value1 = std::string([i.value1 UTF8String]);
    iCpp->value2 = std::string([i.value2 UTF8String]);
    iCpp->value3 = std::string([i.value3 UTF8String]);
    CustomObjectCpp *jCpp = new CustomObjectCpp();
    jCpp->value1 = std::string([j.value1 UTF8String]);
    jCpp->value2 = std::string([j.value2 UTF8String]);
    jCpp->value3 = std::string([j.value3 UTF8String]);
    helloWorld.BenchmarkObjectTen(aCpp, bCpp, cCpp, dCpp, eCpp, fCpp, gCpp, hCpp, iCpp, jCpp);
}

- (void) benchmarkSettingValue:(CustomObject*) obj {
    HelloWorld helloWorld;
    CustomObjectCpp *objCpp = new CustomObjectCpp();
    objCpp->value1 = std::string([obj.value1 UTF8String]);
    objCpp->value2 = std::string([obj.value2 UTF8String]);
    objCpp->value3 = std::string([obj.value3 UTF8String]);
    helloWorld.BenchmarkSettingValue(objCpp);
    obj.value1 = [NSString stringWithUTF8String:objCpp->value1.c_str()];
    obj.value2 = [NSString stringWithUTF8String:objCpp->value2.c_str()];
    obj.value3 = [NSString stringWithUTF8String:objCpp->value3.c_str()];
}

- (NSArray*) benchmarkSettingLargeArray:(NSArray*) largeArray :(NSInteger)size {
    NSMutableArray *mutableArray = [largeArray mutableCopy];
    for (int32_t i = 0; i < int32_t(size); ++i) {
        [mutableArray replaceObjectAtIndex:i withObject:[NSNumber numberWithInteger:i]];
    }
    
    largeArray = [NSArray arrayWithArray:mutableArray];
    return largeArray;
}

@end
